package com.smasher.nfc.protocol.nfcv

import android.annotation.SuppressLint
import android.nfc.Tag
import android.nfc.tech.NfcV
import android.nfc.tech.TagTechnology
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import java.io.IOException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
 * Command Code (Hex)	Command Name	Description
 * 0x2B	INVENTORY	请求标签识别，返回标签的 UID。
 * 0x26	STAY QUIET	请求标签保持静默，直到接收到新的 INVENTORY 命令。
 * 0x25	GET SYSTEM INFORMATION	请求标签的系统信息，如总块数、制造商 ID 等。
 * 0x23	READ SINGLE BLOCK	读取一个特定的数据块。
 * 0x24	READ MULTIPLE BLOCKS	读取多个连续的数据块。
 * 0x22	WRITE SINGLE BLOCK	写入一个特定的数据块。
 * 0x21	LOCK BLOCK	锁定一个特定的数据块，使其不可再被修改。
 * 0x27	WRITE AFI	写入应用族标识符（AFI）。
 * 0x28	LOCK AFI	锁定 AFI，使其不可再被修改。
 * 0x29	WRITE DSFID	写入数据结构格式标识符（DSFID）。
 * 0x2A	LOCK DSFID	锁定 DSFID，使其不可再被修改。
 * 0x2C	GET MULTIPLE BLOCK SECURITY STATUS	获取多个块的安全状态。
 */
class NfcVHelper {

    private val configBlock = false
    private val executorService: ExecutorService = Executors.newSingleThreadExecutor()

    private fun closeTagTechnology(technology: TagTechnology) {
        try {
            technology.close()
        } catch (e: Exception) {
            Log.e(TAG, "close tag technology: ", e)
        }
    }

    /**
     * 读取NFC NfcV的数据
     */
    fun readNfcV(tag: Tag) {
        val mNfcV = NfcV.get(tag) ?: return
        executorService.execute {
            try {
                mNfcV.connect()
                mNfcV.use {
                    val tagArray = it.tag.id
                    handler2.sendMessage(Message().apply {
                        obj = tagArray
                        what = WHAT_LOONG
                    })

                    val dsfId = it.dsfId
                    handler2.sendMessage(Message().apply {
                        obj = dsfId
                        what = WHAT_LOONG_DSF
                    })

                    val uid = readUID(it) ?: throw IOException("Failed to read UID")
                    Log.i(TAG, "run: uid: ${uid.contentToString()}")

                    val afiAndDsf =
                        readAFIAndDSF(it) ?: throw IOException("Failed to read AFI and DSF")
                    val afi = afiAndDsf.first
                    val dsf = afiAndDsf.second
                    Log.i(TAG, "run: afi: $afi dsf: $dsf")

                    if (configBlock) {
                        //读卡28个块内容
                        val data = readSingleBlock(0, it)
                    }
                }

            } catch (e: Exception) {
                handleException(e)
            } finally {
                closeTagTechnology(mNfcV)
            }
        }
    }

    private fun handleException(e: Exception) {
        if (e is android.nfc.TagLostException) {
            Log.e(TAG, "Tag was lost during operation: ", e)
            handler2.sendMessage(Message().apply {
                obj = "Tag was lost"
                what = WHAT_ERROR
            })
        } else {
            Log.e(TAG, "run: ", e)
            handler2.sendMessage(Message().apply {
                obj = e.message
                what = WHAT_ERROR
            })
        }
    }

    private fun readUID(nfcV: NfcV): ByteArray? {
        try {
            // 构建 INVENTORY 命令
            val flags = byteArrayOf(0x20) // 使用高数据速率（如果支持）
            val commandCode = byteArrayOf(0x2B) // INVENTORY 操作码
            val command = flags + commandCode

            // 发送命令并接收响应
            val response = nfcV.transceive(command)

            // 解析响应数据，提取 UID
            if (response.size >= 3) {
                // 响应格式：[Flags][Command Code][Status Byte][UID]
                val statusByte = response[2]
                val result = String.format("0x%02X", statusByte)
                Log.i(TAG, "readUID result: $result")
                if (statusByte.toInt() and 0xFF == 0x00) { // 状态字为 0x00 表示成功
                    return response.copyOfRange(3, response.size)
                } else {
                    println("Inventory failed with status byte: $result")
                }
            } else {
                println("Invalid response length")
            }

        } catch (e: IOException) {
            handleException(e)
        }
        return null
    }

    private fun readAFIAndDSF(nfcV: NfcV): Pair<Byte, Byte>? {
        try {
            // 构建 GET SYSTEM INFORMATION 命令
            val flags = byteArrayOf(0x20) // 使用高数据速率（如果支持）
            val commandCode = byteArrayOf(0x25) // GET SYSTEM INFORMATION 操作码
            val command = flags + commandCode

            // 发送命令并接收响应
            val response = nfcV.transceive(command)

            // 解析响应数据，提取 AFI 和 DSFID
            if (response.size >= 7) {
                // 响应格式：[Flags][Command Code][Status Byte][IC Reference][AFI][DSFID][Memory Size...]
                val statusByte = response[2]
                val result = String.format("0x%02X", statusByte)
                Log.i(TAG, "readAFIAndDSF result: $result")
                if (statusByte.toInt() and 0xFF == 0x00) { // 状态字为 0x00 表示成功
                    val afi = response[4] // AFI 在第 5 个字节
                    val dsfid = response[5] // DSFID 在第 6 个字节
                    return Pair(afi, dsfid)
                } else {
                    println("Get System Information failed with status byte: $result")
                }
            } else {
                println("Invalid response length")
            }

        } catch (e: IOException) {
            handleException(e)
        }
        return null
    }


    /**
     * 读取一个位置在position的block
     *
     *  command 数组包含了命令的各个部分：
     * 构建命令：命令格式：[Flags][Command Code][Index Parameter]
     *
     *  Flags: 0x20 表示高数据速率（如果标签支持）。
     *  Command Code: 0x23 表示读取单个块 (READ SINGLE BLOCK)。 0x24 表示 READ MULTIPLE BLOCKS
     *  Parameter: 要读取的块号。(起始块号 和 结束块号) （在这个例子中是 blockNumber）
     *
     *  响应格式：
     *  [Flags][Command Code][Status Byte][block data]
     *
     * @param position 要读取的block位置
     * @return 返回内容字符串
     * @throws IOException
     */
    @Throws(IOException::class)
    fun readSingleBlock(position: Int, nfcV: NfcV): String? {

        try {
            // 命令格式：[Flags][Command Code][Parameter]
            // Flags: 0x20 表示 High Data Rate (如果支持)
            // Command Code: 0x23 表示 READ SINGLE BLOCK
            // Parameter: 要读取的块号
            val command = byteArrayOf(0x20, 0x23, position.toByte())

            // 发送命令并接收响应
            val response = nfcV.transceive(command)

            // 解析响应数据（去掉命令回显和状态字）
            // 响应格式：[Flags][Command Code][Status Byte][data]
            if (response.size >= 3) {
                val flags = response[0]
                val commandCode = response[1]
                val statusByte = response[2]
                val result = "flags=$flags commandCode=$commandCode statusByte=$statusByte"
                Log.i(TAG, "readSingleBlock: $result")
                val data = response.copyOfRange(3, response.size)
                Log.d(TAG, "Read Block $position Data: ${printHexString(data)}")
                return printHexString(data)
            } else {
                Log.e(TAG, "Invalid response length")
            }

        } catch (e: IOException) {
            Log.e(TAG, "readSingleBlock: ", e)
        }
        return null
    }


    private fun createUID(idArray: ByteArray): String {
        val uid = ByteArray(idArray.size)
        for ((j, i) in idArray.indices.reversed().withIndex()) {
            uid[j] = idArray[i]
        }
        return printHexString(uid)
    }

    /**
     * 将byte[]转换成16进制字符串
     *
     * @param data 要转换成字符串的字节数组
     * @return 16进制字符串
     */
    private fun printHexString(data: ByteArray): String {
        val s = StringBuffer()
        for (datum in data) {
            var hex = Integer.toHexString(datum.toInt() and 0xFF)
            if (hex.length == 1) {
                hex = "0$hex"
            }
            s.append(hex)
        }
        return s.toString()
    }

    @SuppressLint("HandlerLeak")
    private val handler2: Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                WHAT_BLOCK -> {
                    val contents = msg.obj as ArrayList<*>
                    for (item in contents) {
                        Log.d(TAG, "data>>$item")
                    }
                }

                WHAT_LOONG -> {
                    val loong = msg.obj as ByteArray
                    val id = String(loong)
                    val uid = createUID(loong)
                    Log.d(TAG, "ID>>$id UID>>$uid")
                }

                WHAT_LOONG_DSF -> {
                    val dsfId = msg.obj as Byte
                    Log.d(TAG, "dsfId>>$dsfId")
                }

                WHAT_ERROR -> {
                    val errorMessage = msg.obj as String
                    Log.e(TAG, "Error: $errorMessage")
                }

                else -> {}
            }
        }
    }

    fun release() {
        executorService.shutdown()
    }

    companion object {
        const val WHAT_BLOCK = 1005
        const val WHAT_LOONG = 1132
        const val WHAT_LOONG_DSF = 1133
        const val WHAT_ERROR = 1134
        const val TAG = "NfcV"
    }
}
